package com.ly.mp.busicen.rule.flow.engine.db;

import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

import org.apache.ibatis.exceptions.TooManyResultsException;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;

import com.ly.mp.busicen.common.helper.SpringContextHolder;


public class BusicenSqlMapper {
	private final BusicenMbEngine busicenMbEngine;
    private final SqlSession sqlSession;
    private final SqlSessionFactory sessionFactory;
    
    public static BusicenSqlMapper create() {
    	return new BusicenSqlMapper();
    }
    
    public static BusicenSqlMapper create(SqlSessionFactory sessionFactory) {
    	return new BusicenSqlMapper(sessionFactory);
    }

    /**
     * 构造方法，默认缓存MappedStatement
     *
     * @param sqlSessionFactory
     */
    public BusicenSqlMapper(SqlSessionFactory sessionFactory) {
    	this.sessionFactory=sessionFactory;
        this.sqlSession = SqlSessionUtils.getSqlSession(sessionFactory);
        this.busicenMbEngine = new BusicenMbEngine(sqlSession.getConfiguration());
    }
    
    /**
     * 构造方法，默认缓存MappedStatement
     *
     * @param sqlSession
     */
    public BusicenSqlMapper() {
    	this.sessionFactory=SpringContextHolder.getBean(SqlSessionFactory.class);
        this.sqlSession = SqlSessionUtils.getSqlSession(sessionFactory);
        this.busicenMbEngine = new BusicenMbEngine(sqlSession.getConfiguration());
    }
    

    /**
     * 获取List中最多只有一个的数据
     *
     * @param list List结果
     * @param <T>  泛型类型
     * @return
     */
    private <T> T getOne(List<T> list) {
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.size() > 1) {
            throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
        } else {
            return null;
        }
    }
    
    private <T> T execute(Supplier<T> supplier){
    	try {
    		return supplier.get();
		} finally {
			SqlSessionUtils.closeSqlSession(sqlSession, sessionFactory);
		}  
    }

    /**
     * 查询返回一个结果，多个结果时抛出异常
     *
     * @param sql 执行的sql
     * @return
     */
    public Map<String, Object> selectOne(String sql) {
    	return execute(()->getOne(selectList(sql)));
    }

    /**
     * 查询返回一个结果，多个结果时抛出异常
     *
     * @param sql   执行的sql
     * @param value 参数
     * @return
     */
    public Map<String, Object> selectOne(String sql, Object value) {
    	return execute(()->getOne(selectList(sql,value)));
    }

    /**
     * 查询返回一个结果，多个结果时抛出异常
     *
     * @param sql        执行的sql
     * @param resultType 返回的结果类型
     * @param <T>        泛型类型
     * @return
     */
    public <T> T selectOne(String sql, Class<T> resultType) {
        return execute(()-> getOne(selectList(sql, resultType)));
    }

    /**
     * 查询返回一个结果，多个结果时抛出异常
     *
     * @param sql        执行的sql
     * @param value      参数
     * @param resultType 返回的结果类型
     * @param <T>        泛型类型
     * @return
     */
    public <T> T selectOne(String sql, Object value, Class<T> resultType) {
        return execute(()-> getOne(selectList(sql, value, resultType)));
    }

    /**
     * 查询返回List<Map<String, Object>>
     *
     * @param sql 执行的sql
     * @return
     */
    public List<Map<String, Object>> selectList(String sql) {
        String msId = busicenMbEngine.select(sql);
        return execute(()-> sqlSession.selectList(msId));
    }

    /**
     * 查询返回List<Map<String, Object>>
     *
     * @param sql   执行的sql
     * @param value 参数
     * @return
     */
    public List<Map<String, Object>> selectList(String sql, Object value) {
        Class<?> parameterType = value != null ? value.getClass() : null;
        String msId = busicenMbEngine.selectDynamic(sql, parameterType);
        return execute(()-> sqlSession.selectList(msId, value));
    }

    /**
     * 查询返回指定的结果类型
     *
     * @param sql        执行的sql
     * @param resultType 返回的结果类型
     * @param <T>        泛型类型
     * @return
     */
    public <T> List<T> selectList(String sql, Class<T> resultType) {
        String msId;
        if (resultType == null) {
            msId = busicenMbEngine.select(sql);
        } else {
            msId = busicenMbEngine.select(sql, resultType);
        }
        return execute(()-> sqlSession.selectList(msId));
    }

    /**
     * 查询返回指定的结果类型
     *
     * @param sql        执行的sql
     * @param value      参数
     * @param resultType 返回的结果类型
     * @param <T>        泛型类型
     * @return
     */
    public <T> List<T> selectList(String sql, Object value, Class<T> resultType) {
        String msId;
        Class<?> parameterType = value != null ? value.getClass() : null;
        if (resultType == null) {
            msId = busicenMbEngine.selectDynamic(sql, parameterType);
        } else {
            msId = busicenMbEngine.selectDynamic(sql, parameterType, resultType);
        }
        return execute(()->sqlSession.selectList(msId, value));
    }
    

    /**
     * 插入数据
     *
     * @param sql 执行的sql
     * @return
     */
    public int insert(String sql) {
        String msId = busicenMbEngine.insert(sql);
        return execute(()->sqlSession.insert(msId));
    }

    /**
     * 插入数据
     *
     * @param sql   执行的sql
     * @param value 参数
     * @return
     */
    public int insert(String sql, Object value) {
        Class<?> parameterType = value != null ? value.getClass() : null;
        String msId = busicenMbEngine.insertDynamic(sql, parameterType);
        return execute(()-> sqlSession.insert(msId, value));
    }

    /**
     * 更新数据
     *
     * @param sql 执行的sql
     * @return
     */
    public int update(String sql) {
        String msId = busicenMbEngine.update(sql);
        return execute(()-> sqlSession.update(msId));
    }

    /**
     * 更新数据
     *
     * @param sql   执行的sql
     * @param value 参数
     * @return
     */
    public int update(String sql, Object value) {
        Class<?> parameterType = value != null ? value.getClass() : null;
        String msId = busicenMbEngine.updateDynamic(sql, parameterType);
        return execute(()-> sqlSession.update(msId, value));
    }

    /**
     * 删除数据
     *
     * @param sql 执行的sql
     * @return
     */
    public int delete(String sql) {
        String msId = busicenMbEngine.delete(sql);
        return execute(()-> sqlSession.delete(msId));
    }

    /**
     * 删除数据
     *
     * @param sql   执行的sql
     * @param value 参数
     * @return
     */
    public int delete(String sql, Object value) {
        Class<?> parameterType = value != null ? value.getClass() : null;
        String msId = busicenMbEngine.deleteDynamic(sql, parameterType);
        return execute(()->sqlSession.delete(msId, value));
    }

}
